package com.example.basecommon.utils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Repository;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Repository
public class ContextUtil implements InitializingBean, ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(ContextUtil.class);
    private static final Cache<String, String> PROPERTY_CACHE = CacheBuilder.newBuilder().expireAfterWrite(300L, TimeUnit.SECONDS).maximumSize(10000).build();
    public static volatile ApplicationContext applicationContext;
    private static volatile ContextUtil instance;

    public static String getEnvConfig(String key) {
        return getEnvConfig(key, (String) null);
    }

    public static String getEnvConfig(String key, String defaultValue) {
        if (applicationContext != null) {
            String cacheValue = PROPERTY_CACHE.getIfPresent(key);
            if (cacheValue != null) {
                return cacheValue;
            }
            Environment environment = applicationContext.getEnvironment();
            String property = environment.getProperty(key);
            if (property != null) {
                PROPERTY_CACHE.put(key, property);
            } else {
                property = defaultValue;
            }
            return property;
        } else {
            return defaultValue;
        }
    }

    public static Object getBean(String beanName) {
        if (applicationContext != null) {
            try {
                return applicationContext.getBean(beanName);
            } catch (NoSuchBeanDefinitionException e) {
                return null;
            }
        }
        return null;
    }

    public static <T> T getBean(Class<T> clazz) {
        if (applicationContext != null) {
            try {
                return applicationContext.getBean(clazz);
            } catch (NoSuchBeanDefinitionException e) {
                return null;
            }
        }
        return null;
    }

    public static <T> T getBean(String beanName, Class<T> clazz) {
        if (applicationContext != null) {
            try {
                return applicationContext.getBean(beanName, clazz);
            } catch (NoSuchBeanDefinitionException e) {
                return null;
            }
        }
        return null;
    }

    public static <T> Map<String, T> getBeansForType(Class<T> clazz) {
        if (applicationContext != null) {
            try {
                return (Map) applicationContext.getBeansOfType(clazz);
            } catch (NoSuchBeanDefinitionException e) {
                return null;
            }
        }
        return null;
    }

    private static ContextUtil getInstance() {
        return instance;
    }

    @Override
    public void afterPropertiesSet() {
        ContextUtil.instance = this;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ContextUtil.applicationContext = applicationContext;
    }
}
